package device

import (
	"errors"
	"fmt"
	"regexp"
	"strings"
	"time"
	"go-iot/app/iot/core"
	"gorm.io/gorm"
	"go-iot/app/models"
	"go-iot/app/common/mysql"
	"encoding/json"
)

func DeviceIdValid(deviceId string) bool {
	matched, _ := regexp.Match("^[0-9a-zA-Z_\\-]+$", []byte(deviceId))
	return matched
}

// 分页查询设备
func PageDevice(page *models.PageQuery, createId *int64) (*models.PageResult[models.Device], error) {
    var devices []models.Device
    var total int64

    // 构建查询
    query := mysql.DB.Model(&models.Device{})
    
    // 添加创建者条件
    if createId != nil {
        query = query.Where("create_id = ?", *createId)
    }
	
    // 添加条件过滤
    for _, condition := range page.Condition {
		query = query.Where(condition.Key+" = ?", condition.Value)
    }

    // 获取总数
    if err := query.Count(&total).Error; err != nil {
        return nil, fmt.Errorf("查询总数失败: %v", err)
    }

    // 执行分页查询
    if err := query.Order("create_time desc, id desc").
        Offset(page.PageOffset()).
        Limit(page.PageSize).
        Find(&devices).Error; err != nil {
        return nil, fmt.Errorf("分页查询失败: %v", err)
    }

    result := models.PageUtil(total, page.PageNum, page.PageSize, devices)
    return &result, nil
}

func ListClientDeviceByProductId(productId string) ([]string, error) {
    var devices []models.Device
    
    result := mysql.DB.Model(&models.Device{}).
        Where("product_id = ? AND state = ?", productId, core.OFFLINE).
        Select("id").
        Find(&devices)
    
    if result.Error != nil {
        return nil, fmt.Errorf("查询设备列表失败: %v", result.Error)
    }

    ids := make([]string, len(devices))
    for i, device := range devices {
        ids[i] = device.Id
    }
    
    return ids, nil
}

func AddDevice(ob *models.DeviceModel) error {
	if len(ob.Id) == 0 || len(ob.Name) == 0 {
		return errors.New("id, name must be present")
	}
	if len(ob.Id) > 32 {
		return errors.New("设备ID长度不能超过32")
	}
	if !DeviceIdValid(ob.Id) {
		return errors.New("设备ID格式错误")
	}
	ob.DeviceType = strings.TrimSpace(ob.DeviceType)
	if len(ob.DeviceType) == 0 {
		ob.DeviceType = core.DEVICE
	}
	if ob.DeviceType == core.SUBDEVICE {
		if len(ob.ParentId) == 0 {
			return errors.New("子设备需要指定parentId")
		}
		gw, err := GetDevice(ob.ParentId)
		if err != nil {
			return err
		}
		if gw == nil {
			return errors.New("网关不存在")
		}
		if gw.DeviceType != core.GATEWAY {
			return errors.New("父级设备不是网关")
		}
	} else {
		ob.ParentId = ""
	}
	
	// 检查设备是否已存在
	var count int64
	if err := mysql.DB.Model(&models.Device{}).Where("id = ?", ob.Id).Count(&count).Error; err != nil {
		return fmt.Errorf("检查设备是否存在失败: %v", err)
	}
	if count > 0 {
		return errors.New("设备已存在")
	}

	// 创建设备
	MetaConfig, err := json.Marshal(ob.MetaConfig)
	if err != nil {
		return fmt.Errorf("序列化配置信息失败: %v", err)
	}

	device := &models.Device{
		Id:         ob.Id,
		ProductId:  ob.ProductId,
		Name:       ob.Name,
		DeviceType: ob.DeviceType,
		ParentId:   ob.ParentId,
		State:      core.NoActive,
		Desc:       ob.Desc,
		CreateId:   ob.CreateId,
		CreateTime: time.Now(),
		MetaConfig: string(MetaConfig),
	}

	if err := mysql.DB.Create(device).Error; err != nil {
		return fmt.Errorf("创建设备失败: %v", err)
	}

	return nil
}

func UpdateDevice(ob *models.Device) error {
	if len(ob.Id) == 0 {
		return errors.New("设备ID不能为空")
	}

	// 构建更新字段
	updates := make(map[string]interface{})
	if len(ob.Name) > 0 {
		updates["name"] = ob.Name
	}
	if len(ob.Desc) > 0 {
		updates["desc"] = ob.Desc
	}
	if len(ob.MetaConfig) > 0 {
		updates["meta_config"] = ob.MetaConfig
	}
	
	if len(updates) == 0 {
		return errors.New("没有需要更新的数据")
	}

	// 执行更新
	result := mysql.DB.Model(&models.Device{}).
		Where("id = ?", ob.Id).
		Updates(updates)
	
	if result.Error != nil {
		return fmt.Errorf("更新设备失败: %v", result.Error)
	}
	
	if result.RowsAffected == 0 {
		return errors.New("设备不存在或没有字段被更新")
	}

	return nil
}

// 更新在线状态
func UpdateOnlineStatus(id string, state string) error {
	if len(id) == 0 {
		return errors.New("id must be present")
	}
	err := UpdateOnlineStatusList([]string{id}, state)
	if err != nil {
		return err
	}
	return nil
}

func UpdateOnlineStatusList(ids []string, state string) error {
    if len(ids) == 0 {
        return errors.New("ids must be present")
    }
    if len(state) == 0 {
        return errors.New("state must be present")
    }

    result := mysql.DB.Model(&models.Device{}).
        Where("id IN ?", ids).
        Update("state", state)
    
    if result.Error != nil {
        return fmt.Errorf("更新设备状态失败: %v", result.Error)
    }

    return nil
}

func DeleteDevice(deviceId string) error {
	if len(deviceId) == 0 {
		return errors.New("设备ID不能为空")
	}

	result := mysql.DB.Where("id = ?", deviceId).Delete(&models.Device{})
	if result.Error != nil {
		return fmt.Errorf("删除设备失败: %v", result.Error)
	}

	if result.RowsAffected == 0 {
		return errors.New("设备不存在")
	}

	return nil
}

func GetDevice(deviceId string) (*models.DeviceModel, error) {
	if len(deviceId) == 0 {
		return nil, errors.New("deviceId must be present")
	}
	
	var device models.Device
	result := mysql.DB.Where("id = ?", deviceId).First(&device)
	
	if result.Error != nil {
		if errors.Is(result.Error, gorm.ErrRecordNotFound) {
			return nil, nil
		}
		return nil, result.Error
	}
	
	m := &models.DeviceModel{}
	m.FromEnitty(device)
	return m, nil
}

func GetDeviceMust(deviceId string) (*models.DeviceModel, error) {
	p, err := GetDevice(deviceId)
	if err != nil {
		return nil, err
	} else if p == nil {
		return nil, fmt.Errorf("device [%s] not exist", deviceId)
	}
	return p, nil
}

func GetDeviceAndCheckCreateId(deviceId string, createId int64) (*models.DeviceModel, error) {
	ob, err := GetDeviceMust(deviceId)
	if err != nil {
		return nil, err
	}
	if ob.CreateId != createId {
		return nil, errors.New("device is not you created")
	}
	return ob, nil
}

func CountDeviceByProductId(productId string) (int64, error) {
	if len(productId) == 0 {
		return -1, errors.New("productId must be present")
	}
	
	var count int64
	err := mysql.DB.Model(&models.Device{}).
		Where("product_id = ?", productId).
		Count(&count).Error
	
	if err != nil {
		return -1, fmt.Errorf("统计设备数量失败: %v", err)
	}
	
	return count, nil
}
